Writing Game DialogueLoading and Running Yarn ScriptsOn this pageLoading and Running Yarn Scripts Welcome to the YarnRunner library usage tutorial. In this guide, we'll show you how to load and run the Yarn narrative script you wrote in the previous tutorial. 1. Initializing YarnRunner LuaTealTypeScriptYueScriptFirst, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:init.lualocal Content <const> = require("Content")local Path <const> = require("Path")local Node <const> = require("Node")local Director <const> = require("Director")local YarnRunner <const> = require("YarnRunner")To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:init.lualocal path = Path:getScriptPath(...)Content:insertSearchPath(1, path)Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:init.lualocal runner = YarnRunner("tutorial.yarn", "Start")First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:init.tllocal Content <const> = require("Content")local Path <const> = require("Path")local Node <const> = require("Node")local Director <const> = require("Director")local YarnRunner <const> = require("YarnRunner")To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:init.tllocal path = Path:getScriptPath(...)Content:insertSearchPath(1, path)Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:init.tllocal runner = YarnRunner("tutorial.yarn", "Start")First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:init.tsimport { Content, Path, Node, Director } from "Dora";import * as YarnRunner from "YarnRunner";To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:init.tsconst path = Path.getScriptPath(...);Content.insertSearchPath(1, path);Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:init.tsconst runner = YarnRunner("tutorial.yarn", "Start");First, make sure you have imported all the necessary modules.init.yue_ENV = Doraimport "YarnRunner"To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:init.yuepath = Path\getScriptPath ...Content\insertSearchPath 1, pathNext, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:init.yuerunner = YarnRunner "tutorial.yarn", "Start" 2. Executing and Displaying Narrative Content We define an advance function that can read and display text or options from the Yarn script. Based on the content, it can also display the character's name: LuaTealTypeScriptYueScriptinit.lua-- The advance function takes an optional integer representing the player's choice index.-- For the first call or when no choice is needed, we pass nil.local function advance(option) -- First, we call runner:advance(option) to get the next part of the Yarn script. -- This returns two values: an action type and a result. local action, result = runner:advance(option) -- Handle the result based on the action type. if action == "Text" then -- If the action is "Text", the result will be a TextResult object, -- containing the text and any associated markers (e.g., character names). -- Check the markers, extract the character's name (if present), and print the text. local characterName = "" local marks = result.marks if marks then for i = 1, #marks do local mark = marks[i] if mark.name == "char" then characterName = mark.attrs.name .. ": " end end end print(characterName .. result.text) elseif action == "Option" then -- If the action is "Option", the result will be an OptionResult object, -- containing one or more options. Iterate over the options and print them, -- allowing the player to select them later. for i, op in ipairs(result) do if op then print("[" .. tostring(i) .. "]: " .. op.text) end end else -- For other actions (like errors), print the result directly. print(result) endendinit.tl-- The advance function takes an optional integer representing the player's choice index.-- For the first call or when no choice is needed, we pass nil.local function advance(option?: integer) -- First, we call runner:advance(option) to get the next part of the Yarn script. -- This returns two values: an action type and a result. local action, result = runner:advance(option) -- Handle the result based on the action type. if action == "Text" then -- If the action is "Text", the result will be a TextResult object, -- containing the text and any associated markers (e.g., character names). local textResult = result as YarnRunner.TextResult -- Check the markers, extract the character's name (if present), and print the text. local characterName = "" local marks = textResult.marks if not (marks is nil) then for i = 1, #marks do local mark = marks[i] if mark.name == "char" then characterName = tostring(mark.attrs.name) .. ": " end end end print(characterName .. textResult.text) elseif action == "Option" then -- If the action is "Option", the result will be an OptionResult object, -- containing one or more options. Iterate over the options and print them, -- allowing the player to select them later. local optionResult = result as YarnRunner.OptionResult for i, op in ipairs(optionResult) do if op and not (op is boolean) then print("[" .. tostring(i) .. "]: " .. op.text) end end else -- For other actions (like errors), print the result directly. print(result) endendinit.ts// The advance function takes an optional integer representing the player's choice index.// For the first call or when no choice is needed, we pass null.function advance(option?: number): void { // First, we call runner.advance(option) to get the next part of the Yarn script. // This returns two values: an action type and a result. const [action, result] = runner.advance(option); // Handle the result based on the action type. switch (action) { case "Text": // If the action is "Text", the result will be a TextResult object, // containing the text and any associated markers (e.g., character names). // Check the markers, extract the character's name (if present), and print the text. let characterName = ""; const marks = result.marks; if (marks) { for (const mark of marks) { if (mark.name === "char") { characterName = `${mark.attrs?.name}: `; } } } print(characterName + result.text); break; case "Option": // If the action is "Option", the result will be an OptionResult object, // containing one or more options. Iterate over the options and print them, // allowing the player to select them later. const optionResult = result; for (let i = 0; i < optionResult.length; i++) { const op = optionResult[i]; if (op && op !== true) { print(`[${i}]: ${op.text}`); } } break; default: // For other actions (like errors), print the result directly. print(result); break; }}init.yue-- The advance function takes an optional integer representing the player's choice index.-- For the first call or when no choice is needed, we pass nil.advance = (option) -> -- First, call runner\advance to get the next part of the Yarn script. -- This returns two values: an action type and a result. action, result = runner\advance option -- Handle the result based on the action type. switch action when "Text" -- If the action is "Text", the result will be a TextResult object, -- containing the text and any associated markers (e.g., character names). -- Check the markers, extract the character's name (if present), and print the text. charName = "" if result.marks for mark in *result.marks switch mark when {name: attr, attrs: {:name}} charName = "#{name}: " if attr == "char" print charName .. result.text when "Option" -- If the action is "Option", the result will be an OptionResult object, -- containing one or more options. Iterate over the options and print them, -- allowing the player to select them later. for i, op in ipairs result print "[#{i}]: #{op.text}" if op else -- For other actions (like errors), print the result directly. print result 3. Starting the Narrative To start the narrative, simply call the advance function without any arguments: LuaTealTypeScriptYueScriptinit.luaadvance()init.tladvance()init.tsadvance();init.yueadvance! 4. Handling User Input To enable player interaction, we need a node to capture and respond to user input. We create a node and assign it a signal slot named "go". When this signal is triggered, it will call the advance function again, passing the player's choice: LuaTealTypeScriptYueScriptinit.lualocal node = Node()node:gslot("go", function(option) advance(option)end)node:addTo(Director.entry)init.tllocal node = Node()node:gslot("go", function(option: nil | integer) advance(option)end)node:addTo(Director.entry)init.tsconst node = Node();node.gslot("go", (option: number | null) => { advance(option);});node.addTo(Director.entry);init.yuewith Node! \gslot "go", (option) -> advance option \addTo Director.entry Here, we registered a global event listener for quick testing. In actual game development, you'd need to write the UI interaction logic. Once this "go" global event listener is set, you can use the Dora SSR console to input emit 'go' to continue the dialogue, or emit 'go', 1 to select dialogue branches for interactive test runs. 5. Adding Custom Commands and State You can add custom commands and initial state variables by passing the command and state parameters to YarnRunner. The command parameter is a Lua table containing callback functions for commands, and state is a table with predefined variables. Here’s an example: LuaTealTypeScriptYueScriptinit.lualocal runner = YarnRunner("tutorial.yarn", "Start", { playerScore = 100}, { print = print})init.tllocal runner = YarnRunner("tutorial.yarn", "Start", { playerScore = 100}, { print = print})init.tsconst runner = YarnRunner("tutorial.yarn", "Start", { playerScore: 100}, { print: print})init.yuerunner = YarnRunner "tutorial.yarn", "Start", { playerScore: 100}, { print: print} Then, in the Yarn script, you can modify initial variable values using <<set $variable = expression>> and print variables using the custom command <<print $variable>>: Test Dialogue Node<<set $playerScore = $playerScore + 200>><<print $playerScore>> 6. Conclusion Now, you have set up all the necessary code to load and run Yarn narrative scripts. You can run the above script to begin your interactive narrative, where players can interact by selecting options. Happy creating!